package org.tio.sitexxx.service.service.base;

import java.sql.SQLException;
import java.util.List;
import java.util.Objects;

import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.sitexxx.service.cache.CacheConfig;
import org.tio.sitexxx.service.cache.Caches;
import org.tio.sitexxx.service.model.main.IpInfo;
import org.tio.sitexxx.service.model.main.User;
import org.tio.sitexxx.service.model.main.UserlogModifyAvatar;
import org.tio.sitexxx.service.model.main.UserlogModifyNick;
import org.tio.sitexxx.service.service.conf.ConfService;
import org.tio.sitexxx.service.service.tiosite.BlogService;
import org.tio.sitexxx.service.vo.Const;
import org.tio.utils.cache.CacheUtils;
import org.tio.utils.cache.FirsthandCreater;
import org.tio.utils.cache.ICache;
import org.tio.utils.cache.redis.RedisCache;
import org.tio.utils.json.Json;
import org.tio.utils.resp.Resp;

import com.jfinal.kit.Ret;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;

/**
 * @author tanyaowu
 * 2016年8月10日 上午11:09:59
 */
public class UserService {
	private static Logger log = LoggerFactory.getLogger(UserService.class);

	public static final UserService ME = new UserService();

	public static final RoleService roleService = RoleService.me;

	/**
	 * @param args
	 * @author tanyaowu
	 */
	public static void main(String[] args) {
	}

	public final User userDao = new User().dao();

	public static final User nullUser = new User();

	ICache loginnameAndUserCache;

	ICache useridAndUserCache;

	/**
	 *
	 * @author tanyaowu
	 */
	private UserService() {
		loginnameAndUserCache = Caches.getCache(CacheConfig.LOGINNAME_USER);
		useridAndUserCache = Caches.getCache(CacheConfig.USERID_USER);
	}

	/**
	 * 对用户进行增、删、改后都要调一下这个方法
	 * @param userid
	 * @param loginname
	 * @author tanyaowu
	 */
	public void clearCache(Integer userid, String loginname) {
		if (userid != null) {
			useridAndUserCache.remove(userid + "");
		}
		if (StrUtil.isNotBlank(loginname)) {
			loginnameAndUserCache.remove(loginname);
		}
	}

	/**
	 * 清除所有的用户缓存
	 */
	public void clearAllUserCache() {
		useridAndUserCache.clear();
		loginnameAndUserCache.clear();
	}

	/**
	 * 所有用户，包括各种状态，调用后根据业务进行状态处理
	 * @param id
	 * @return
	 * @author tanyaowu
	 */
	public User getById(Integer id) {
		if (id == null) {
			return null;
		}
		String key = id + "";

		User user1 = CacheUtils.get(useridAndUserCache, key, true, new FirsthandCreater<User>() {
			@Override
			public User create() {
				User user = userDao.findById(id);

				if (user == null) {
					return null;
				}

				roleService.setRoles(user);

				IpInfo ipInfo = IpInfoService.ME.getById(user.getIpid());
				user.setIpInfo(ipInfo);

				if (StrUtil.isBlank(user.getAvatar())) {
					user.setAvatar(User.DEFAULT_AVATAR);
				}

				if (StrUtil.isBlank(user.getAvatarbig())) {
					user.setAvatarbig(user.getAvatar());
				}

				return user;
			}
		});
		return user1;
	}

	/**
	 * 所有状态下的用户，调用后，根据业务进行处理
	 * @param id
	 * @return
	 * @author: tanyaowu
	 */
	public User getById(String id) {
		if (StrUtil.isBlank(id)) {
			return null;
		}

		return getById(Integer.parseInt(id));
	}

	/**
	 * 保存用户，会连着保存ip等信息
	 * @param user
	 * @return
	 * @author tanyaowu
	 */
	public User save(User user) {
		IpInfo ip = user.getIpInfo();
		ip = IpInfoService.ME.save(ip);

		if (ip != null) {
			user.setIpid(ip.getId());
			boolean ff = user.save();
			if (ff) {
				user.setIpInfo(ip);
				return user;
			}
		}
		return null;
	}

	/**
	 * 保存唯一用户
	 * @param user
	 * @return
	 */
	public User userUnionSave(User user) {
		return null;
	}

	/**
	 * 获取用户数
	 * @return
	 */
	public int getUserCount() {
		ICache cache = Caches.getCache(CacheConfig.USER_COUNT);
		String key = org.tio.sitexxx.service.cache.Caches.SINGLE_KEY;

		Integer count = CacheUtils.get(cache, key, true, new FirsthandCreater<Integer>() {
			@Override
			public Integer create() {
				String sql = "select count(*) from user";
				return Db.use(Const.Db.TIO_SITE_MAIN).queryInt(sql);
			}
		});

		return count;
	}

	/**
	 * 根据loginname获取用户
	 * @param loginname
	 * @param status 如果为null则不限状态
	 * @return
	 * @author tanyaowu
	 */
	public User getByLoginname(String loginname, Byte status) {
		User user = (User) loginnameAndUserCache.get(loginname);
		if (user == null) {
			user = userDao.findFirst("select * from user where loginname = ? and `status` <> ?", loginname, org.tio.sitexxx.service.model.main.User.Status.LOGOUT);
			if (user != null) {
				user = getById(user.getId());
			}
			if (user != null) {
				loginnameAndUserCache.put(loginname, user);
			} else {
				loginnameAndUserCache.putTemporary(loginname, nullUser);
			}
		} else {
			//可能是 nullUser
			if (user.getId() == null) {
				return null;
			}
			if (status == null) {
				return user;
			}
			if (!Objects.equals(status, user.getStatus())) {
				return null;
			}
		}
		return user;
	}

	/**
	 * 1、loginname不存在
	 * 2、密码不正确
	 * 3、换aes登录吧
	 * @param loginname
	 * @param pwd 明文，用于兼容，升级过的是可以不传的
	 * @param pd5 md5加密的密码
	 * @return
	 */
	public Ret login(String loginname, String pwd, String pd5) {
		String code = "code";
		if (StrUtil.isBlank(loginname)/** || ( StrUtil.isBlank(pwd) &&  !isThirdLogin) */
		) {
			return Ret.fail();
		}
		User user = getByLoginname(loginname, null);
		if (user == null) {
			log.info("can find user by loginname:【{}】", loginname);
			return Ret.fail(code, 1); //loginname不存在
		}

		if (!Objects.equals(pd5, user.getPwd())) {
			log.info("password is invalid, loginname:[{}], md5pwd:[{}], need md5pwd:[{}]", loginname, pd5, user.getPwd());
			return Ret.fail(code, 2); //密码不正确 
		}

		return Ret.ok("user", user);
	}

	/**
	 * 修改用户昵称
	 * @param user
	 * @param newNick
	 * @return
	 * @author tanyaowu
	 */
	public Resp updateNick(User user, String newNick) {
		if (!isSupper(user)) {
			if (StrUtil.containsAny(newNick, Const.SPECIAL_CHARACTER)) {
				return Resp.fail("昵称不能包含如下特殊字符：" + Json.toJson(Const.SPECIAL_CHARACTER));
			}
		}

		if (newNick.equals(user.getNick())) {
			return Resp.fail("原来的昵称就是这个哦！");
		}

		UserlogModifyNick userlogModifyNick = new UserlogModifyNick();
		userlogModifyNick.setNewnick(newNick);
		userlogModifyNick.setOldnick(user.getNick());
		userlogModifyNick.setUid(user.getId());

		if (StrUtil.isNotBlank(newNick)) {
			Integer check = Db.use(Const.Db.TIO_SITE_MAIN).queryInt("select id from user where nick = ? and id != ? and `status` != ? limit 1", newNick, user.getId(),
			        org.tio.sitexxx.service.model.main.User.Status.LOGOUT);
			if (check != null) {
				return Resp.fail("昵称已存在");
			}
			//			user.setSrcnick(newNick);
			String filterContent = newNick;
			filterContent = SensitiveWordsService.findAndReplace(filterContent);
			filterContent = StringEscapeUtils.escapeHtml4(filterContent);
			user.setNick(filterContent);
		}
		String loginname = user.getLoginname();
		String sql = "update user set nick = ? where id = ?";
		int c = Db.update(sql, newNick, user.getId());

		if (c < 1) {
			return Resp.fail("用户昵称修改失败");
		}
		clearCache(user.getId(), loginname);

		userlogModifyNick.save();
		return Resp.ok().msg("用户昵称修改成功");
	}

	/**
	 * 更新头像
	 * @param user
	 * @param newavatar
	 * @param newavatarbig
	 * @return
	 * @author tanyaowu
	 */
	public Resp updateAvatar(User user, String newavatar, String newavatarbig) {
		UserlogModifyAvatar userlogModifyAvatar = new UserlogModifyAvatar();
		userlogModifyAvatar.setNewavatar(newavatar);
		userlogModifyAvatar.setNewavatarbig(newavatarbig);
		userlogModifyAvatar.setOldavatar(user.getAvatar());
		userlogModifyAvatar.setOldavatarbig(user.getAvatarbig());
		userlogModifyAvatar.setUid(user.getId());

		String loginname = user.getLoginname();
		String sql = "update user set avatar = ?, avatarbig = ? where id = ?";
		int c = Db.update(sql, newavatar, newavatarbig, user.getId());

		if (c < 1) {
			return Resp.fail("用户头像修改失败");
		}
		clearCache(user.getId(), loginname);

		userlogModifyAvatar.save();
		return Resp.ok().msg("用户头像修改成功");
	}

	public Resp addRoleByLoginname(String loginname, byte roleid) {
		User user = getByLoginname(loginname, org.tio.sitexxx.service.model.main.User.Status.NORMAL);
		if (user == null) {
			return Resp.fail("用户不存在或状态不正常");
		}
		return addRole(user, roleid);
	}

	public Resp addRoleByNick(String nick, byte roleid) {
		Integer uid = getUidByNick(nick);
		if (uid == null) {
			return Resp.fail("昵称不存在");
		}

		User user = getById(uid);

		if (user == null) {
			return Resp.fail("用户不存在");
		}

		if (!Objects.equals(user.getStatus(), org.tio.sitexxx.service.model.main.User.Status.NORMAL)) {
			return Resp.fail("用户状态不对");
		}

		return addRole(user, roleid);
	}

	/**
	 * 给某用户添加角色
	 * @param loginname
	 * @param roleid
	 * @return
	 * @author tanyaowu
	 */
	public Resp addRole(User user, byte roleid) {
		if (user == null) {
			return Resp.fail("用户为空");
		}

		boolean f = Db.use(Const.Db.TIO_SITE_MAIN).tx(new IAtom() {
			@Override
			public boolean run() throws SQLException {
				//先删除
				String sql = "delete from user_role where uid = ? and rid = ?";
				Db.use(Const.Db.TIO_SITE_MAIN).update(sql, user.getId(), roleid);

				//再添加
				sql = "insert into user_role (uid, rid, status) values (?,?,?)";
				Db.use(Const.Db.TIO_SITE_MAIN).update(sql, user.getId(), roleid, 1);

				return true;
			}

		});

		if (f) {
			clearCache(user.getId(), user.getLoginname());
			return Resp.ok();
		} else {
			return Resp.fail("操作失败");
		}
	}

	/**
	 * 获取md5加密密码
	 * @param loginname 登录名
	 * @param plainpwd 明文密码
	 * @return
	 */
	public static String getMd5Pwd(String loginname, String plainpwd) {
		String pwd = SecureUtil.md5("${" + StrUtil.trim(loginname) + "}" + StrUtil.trim(plainpwd));
		return pwd;
	}

	/**
	 * 清空用户所有的相关缓存
	 * @param uid
	 * 
	 * @date 2016年11月20日 下午1:45:19
	 */
	public void clearUserALLCache(Integer uid) {
		User user = UserService.ME.getById(uid);
		if (user != null) {
			Caches.getCache(CacheConfig.USERID_USER).remove(uid + "");
			Caches.getCache(CacheConfig.LOGINNAME_USER).remove(user.getLoginname());
		}
	}

	/**
	 * 发topic通知清除用户缓存
	 * @param uid
	 */
	public void notifyClearUserCache(Integer uid) {
		clearUserALLCache(uid);
	}

	/**
	 * 是否是超管，上帝视角
	 * @param user
	 * @return
	 */
	public static final boolean isSupper(User user) {
		if (user == null) {
			return false;
		}
		return UserRoleService.hasRole(user, Const.Role.ADMIN_SUPER);
	}

	/**
	 * 根据用户昵称修改用户状态 (status)
	 * @param nick
	 * @param newStatus
	 * @return
	 */
	public int updateUserStatus(String nick, byte newStatus) {
		if (StrUtil.isBlank(nick)) {
			return 0;
		}

		Integer uid = getUidByNick(nick);
		return updateUserStatus(uid, newStatus);
	}

	/**
	 * 根据uid修改用户状态 (status)
	 * @param uid
	 * @param newStatus
	 * @return
	 */
	public int updateUserStatus(Integer uid, byte newStatus) {
		if (uid == null) {
			return 0;
		}
		String sql = "update user set status = ? where id = ?";
		int c = Db.update(sql, newStatus, uid);

		notifyClearUserCache(uid);

		return c;
	}

	/**
	 * 根据用户昵称拉黑用户
	 * @param nick
	 * @return
	 */
	public int pullBlackUserByNick(String nick) {
		Integer uid = getUidByNick(nick);
		return pullBlackUserByUid(uid);
	}

	/**
	 * 根据uid把用户拉黑
	 * @param uid
	 * @return
	 */
	public int pullBlackUserByUid(Integer uid) {
		int c = updateUserStatus(uid, org.tio.sitexxx.service.model.main.User.Status.INBLACK);
		if (uid != null) {
			List<Integer> blogList = BlogService.getByUid(uid);
			if (blogList != null) {
				for (Integer blogid : blogList) {
					try {
						BlogService.clearCache(blogid);
					} catch (Exception e) {
						log.error(e.toString(), e);
					}
				}
			}
		}
		return c;
	}

	/**
	 * 根据用户昵称将用户的状态改为正常
	 * @param nick
	 * @return
	 */
	public int normalUserByNick(String nick) {
		Integer uid = getUidByNick(nick);
		return normalUserByUid(uid);
	}

	/**
	 * 根据uid将用户的状态改为正常
	 * @param uid
	 * @return
	 */
	public int normalUserByUid(Integer uid) {
		return updateUserStatus(uid, org.tio.sitexxx.service.model.main.User.Status.NORMAL);
	}

	/**
	 * 根据昵称找到uid
	 * @param nick
	 * @return
	 */
	public Integer getUidByNick(String nick) {
		if (StrUtil.isBlank(nick)) {
			return null;
		}
		ICache cache = Caches.getCache(CacheConfig.TIME_TO_LIVE_SECONDS_5);
		String key = "user_nick_id" + RedisCache.SPLIT_FOR_CACHENAME + nick;
		Integer uid = CacheUtils.get(cache, key, true, new FirsthandCreater<Integer>() {
			@Override
			public Integer create() {
				String sql = "select id from user where nick = ?";
				return Db.use(Const.Db.TIO_SITE_MAIN).queryInt(sql, nick);
			}
		});
		return uid;

	}

	/**
	 * 获取智能机器人
	 * @return
	 * @author tanyaowu
	 */
	public User getAi() {
		User user = getByLoginname(ConfService.getString("ai.loginname", "talent@tio.org"), null);
		return user;
	}

}
